他相信著那盞橘燈,這個一年一年在我們眼前變得更加琳瑯滿目的前端框架們。但沒關係,明天將有更多的雲端平台讓我們各種方法佈署更多的前端專案。也許在一個明亮舒適的早晨…
~節錄自《The Great Svelte:第九章》
經過了 30 天的努力,我們終於將色票產生器做的算是有模有樣了,不僅可以透過加減按鈕改變色票的數量,當使用者想要加入/減少的色票數目超出我們願意提供的範圍的時候,跳出互動視窗來阻止這些行為。除此之外,還可以直接輸入我們想要的色碼來直接指定色票的顏色,或是上鎖/解鎖色票,來控制色票是否隨時間發生變化。再加上親切可愛的 toast 提示,來通知使用者當前介面發生的變化。一口氣講完這麼多內容還真是有點累,更別說我們可是一邊學習一邊熟悉,一口氣以 Svelte 這個前端框架實作出了這麼多有趣有迷人的功能。所以在最後這一天,讓我們把辛辛苦苦實作出來的專案發布出來,讓大家都可以享受到這麼棒的色票產生器吧。
不過首先讓我們稍微修改一下色票產生器的功能。我們利用 setInterval
讓色票產生器固定 2000
毫秒就重新產生一組色票,這樣子固然是不錯,不過對使用者來說,也許更實用的功能是做出一個重新產生色票的按鈕,讓使用者可以自由決定是否該產生下一組色票,或是先停留在目前的色票好好研究評估。
所以我們先到 Counter.svelte
,多加上一個按鈕吧:
/src/lib/Counter.svelte
<script>
import { createEventDispatcher } from "svelte";
import shuffle from "../assets/shuffle.svg";
export let count = 100;
const dispatch = createEventDispatcher();
const handleClick = (delta) => {
dispatch("changeCount", delta);
};
const handleShuffle = () => dispatch("shuffle");
</script>
<section>
<h1>Create Color Palette for Me!</h1>
<div class="controller">
<div class="counter">
<button on:click={() => handleClick(-1)}>
<svg aria-hidden="true" viewBox="0 0 1 1">
<path d="M0,0.5 L1,0.5" />
</svg>
</button>
<div class="counter-viewer">
<p>{count}</p>
</div>
<button on:click={() => handleClick(1)}>
<svg aria-hidden="true" viewBox="0 0 1 1">
<path d="M0,0.5 L1,0.5 M0.5,0 L0.5,1" />
</svg>
</button>
</div>
<div class="shuffle">
<button on:click={handleShuffle}>
<p>Shuffle<span><img src={shuffle} alt="shuffle" /></span></p>
</button>
</div>
</div>
</section>
第三行:import shuffle from "../assets/shuffle.svg";
為我們重新產生色票的按鈕先準備一個圖示。
第十三行:const handleShuffle = () => dispatch("shuffle");
同時也準備一個事件處理器 handleShuffle
,當按鈕按下去,就向外部元件送出 shuffle
這個事件。
第三十六行:<div class="shuffle">
替重新產生色票的按鈕準備一個 <div>
。
第三十七行:<button on:click={handleShuffle}>
用 on:click
,接收來自使用的的點擊 (click
) 事件,當事件發生時,就會呼叫 handleShuffle
這個事件處理器來處理該事件,也就是向外部元件送出 shuffle
!
其餘 CSS 的部分可以參考文末附錄,或是完整的程式碼可以到 Github 資源庫閱讀。
接著到 App.svelte
來做一些修改,主要是刪除 setInterval
定時更新色票的功能,以及實作出接收 shuffle
事件並重新產生一組新的色票的程式碼:
/src/App.svelte
<script>
// import { onMount } from "svelte";
/* 省略一些不相關的程式碼 */
/* 加入 handleShuffle */
const handleShuffle = () => {
palettes = palettes.map((palette) => {
if (palette.locked) {
return palette;
} else {
return { ...palette, hex: generateHex() };
}
});
};
// onMount(() => {
// const intervalId = setInterval(() => {
// palettes = palettes.map((palette) => {
// if (palette.locked) {
// return palette;
// } else {
// return { ...palette, hex: generateHex() };
// }
// });
// }, 2000);
// return () => clearInterval(intervalId);
// });
</script>
{#each $toastStore as toast}
<Toast {toast} />
{/each}
<main>
<!-- 在 HTML 當中直接嵌入 Counter -->
<Counter {count} on:changeCount={handleClick} on:shuffle={handleShuffle} />
<!-- 在 HTML 當中直接嵌入 Palettes -->
<Palettes bind:palettes />
<p class="comment">
Check out <a {href}>Svelte Tutorial</a>, the awesome article powered by {sparkle(
someState
)}!
</p>
</main>
<!-- 在 HTML 當中直接嵌入 Modal -->
<Modal {showModal} on:closeModal={() => (showModal = false)} />
第二行:// import { onMount } from "svelte";
因為不打算使用 setInterval
,所以 onMount
目前也用不到了。
第六行:const handleShuffle = () => {
宣告一個函式 handleShuffle
,這個函式將作為 shuffle
事件的事件處理器,只要使用者點擊 <Counter />
當中重新產生色票的按鈕,就會發生 shuffle
事件,就會呼叫這個函式。函式的內容就跟我們先前用 setInterval
來改變色票顏色是相同的做法。如果色票被鎖定 palette.locked
,則不改變該色票的顏色。反之,如果沒有鎖定色票,就用 generateHex()
重新產生一個色碼。
第十六行:// onMount(() => {
就不使用 setInterval
來隨時間重新產生不同顏色的色票了。
第三十七行:<Counter {count} on:changeCount={handleClick} on:shuffle={handleShuffle} />
記得要在 <Counter />
當中加上 on:shuffle={handleShuffle}
,接收來自 <Counter />
的 shuffle
事件,並且當事件發生時呼叫 handleShuffle
這個事件處理器。
圖一、Shuffle!
好的,現在我們的色票產生器這個專案已經蓄勢待發了,就讓我們來看看如何將專案部署出去吧。
現在最主流佈署專案的方式,就是透過雲端運算平台。也就是說,我們只要負責寫好程式碼,並將程式碼送到雲端,或是 Github 等程式碼存放平台上,其他一切伺服器建置以及維護等等相關的工作都由雲端運算平台的開發商來替我們煩惱。
Svelte 官方推薦的雲端平台是 Vercel。不過不同雲端平台提供的基礎服務其實大同小異,加上我只有 Netlify 這個雲端平台的帳號,所以今天我們就嘗試從 Netlify 佈署看看色票產生器這個 Svelte 專案吧。
首先將我們色票產生器的程式碼存放到 Github 資源庫當中。接著來到 Netlify 官方網站,並且登入,就可以看到個人帳號的狀態跟各種操作。點選【Sites】,如圖二,然後【Add new site】,如圖三。
圖二、點選【Sites】。
圖三、點選【Add new site】。
這時候就會進入佈署新專案的流程。預設會是從程式碼存放平台當中匯入程式碼,除此之外還有 Netlify Drop,將已經編譯好的直接發佈的方法。不過現在就不討論這麼多,直接用最常見的方法,從程式碼存放平台匯入。因為我的色票產生器的程式碼是放在 Github 資源庫上面,所以選擇【Deploy with Github】。
圖四、點選【Deploy with Github】
Netlify 並不是可以無條件直接取得我們存放在 Github 資源庫的程式碼,我們的 Github 帳號需要允許 Netlify 這個外部應用程式有讀取的權限。若沒有做設定,可以在這邊點選【Configure the Netlify app on Github】。
圖五、點選【Configure the Netlify app on Github】
到 Github 之後,我們可以在資源庫的存取權限當中,選擇一勞永逸,讓 Netlify 可以讀取所有的資源庫 (All repositories),或是手動勾選願意讓 Netlify 讀取的資源庫 (Only selected repositories)。這邊我選擇手動勾選,然後勾選色票產生器存在的資源庫,也就是【The-Great-Svelte】。
圖六、在 Github 上面設定讀取權限 (Repository Access)。
這麼一來,Netlify 應該就可以看到我們放在 Github 上面的程式碼了。選擇我們存放有我們想要發布的專案的資源庫。
圖七、選擇資源庫。
接下來要做一些發布專案的設定。因為 Github 通常只有最原始的程式碼,而不是準備好已經可以發布出去的內容。以 Svelte 來說,Github 上面放的都是 Svelte 的元件,還沒經過編譯器的處理,還沒有轉換成最後的 Javascript、HTML,以及 CSS,所以並非網頁瀏覽器可以直接解讀的內容。雲端平台的開發商當然也知道這個狀況,所以提供服務幫我們從最原始的程式碼編譯成可供網頁瀏覽器閱讀的內容。不同的前端框架,將原始碼轉換為可發布的成果時,執行編譯的指令不盡相同。以 Svelte 來說,是 npm run build
。而完成編譯的檔案,會放在 dist
這個路徑底下。所以在 Build command 這一欄填入 npm run build
,同時在 Publish directory 填入 dist
。設定完成之後,就按下【Deploy】。
圖八、Build command:npm run build
,Publish directory:dist
然後就完成囉!
圖九、Your site is deployed✅
佈署完成之後,可以在頁面上找到一行網址,以我這次佈署來說,Netlify 給我的網址是:https://peaceful-vacherin-d1fd7c.netlify.app/ 。這一行網址就是我們專案的位置了,這樣就完成了,是不是很簡單呢!
圖十、Shuffle from Netlify
這個系列文就到這邊結束了,所有系列文當中完整的程式碼都可以到 Github 資源庫參考,謝謝大家的閱讀!
Counter.svelte
/src/lib/Counter.svelte
<script>
import { createEventDispatcher } from "svelte";
import shuffle from "../assets/shuffle.svg";
export let count = 100;
const dispatch = createEventDispatcher();
const handleClick = (delta) => {
dispatch("changeCount", delta);
};
const handleShuffle = () => dispatch("shuffle");
</script>
<section>
<h1>Create Color Palette for Me!</h1>
<div class="controller">
<div class="counter">
<button on:click={() => handleClick(-1)}>
<svg aria-hidden="true" viewBox="0 0 1 1">
<path d="M0,0.5 L1,0.5" />
</svg>
</button>
<div class="counter-viewer">
<p>{count}</p>
</div>
<button on:click={() => handleClick(1)}>
<svg aria-hidden="true" viewBox="0 0 1 1">
<path d="M0,0.5 L1,0.5 M0.5,0 L0.5,1" />
</svg>
</button>
</div>
<div class="shuffle">
<button on:click={handleShuffle}>
<p>Shuffle<span><img src={shuffle} alt="shuffle" /></span></p>
</button>
</div>
</div>
</section>
<style>
h1 {
margin: 0.5em 0;
}
.controller {
margin: 0 1em;
display: flex;
justify-content: space-between;
gap: 1em;
}
.controller button {
width: 4em;
height: 4em;
border-radius: var(--border-radius);
background: var(--color-bg-3);
outline: none;
border: none;
cursor: pointer;
}
.controller button:hover {
background: #fff;
}
.shuffle {
width: 100%;
}
.shuffle button {
width: 100%;
}
.counter {
display: flex;
justify-content: center;
}
.counter .counter-viewer {
width: 4em;
display: flex;
justify-content: center;
align-items: center;
}
p {
color: var(--color-text);
font-size: 1.8em;
font-weight: bold;
}
svg {
width: 25%;
height: 25%;
}
path {
vector-effect: non-scaling-stroke;
stroke-width: 2px;
stroke: #444;
}
img {
padding-left: 0.4em;
opacity: 0.5;
}
</style>